<template>
  <div class="theme">
    <el-switch
      ref="switchRef"
      v-model="darkMode"
      v-bind="$attrs"
      :before-change="beforeChange"
      :active-action-icon="DarkIcon"
      :inactive-action-icon="LightIcon"
    />
  </div>
</template>

<script setup>
import { nextTick, ref, watch } from "vue";
import { useDark, useToggle } from "@vueuse/core";
import useSettingStore from "@/store/modules/settings";
import DarkIcon from "../IconFile/dark.vue";
import LightIcon from "../IconFile/light.vue";
const settingStore = useSettingStore();
const switchRef = ref();
const isDark = useDark({
  storageKey: "vue3-theme-appearance",
});
const darkMode = ref(isDark.value);
const toggleDark = useToggle(isDark);

// 监听 `isDark` 的变化
watch(
  isDark,
  (newVal) => {
    const mode = newVal ? "dark" : "light";
    document.documentElement.setAttribute("data-theme", mode);
    settingStore.setDataTheme(mode);
  },
  {
    immediate: true,
  }
);
watch(
  () => darkMode.value,
  () => {
    toggleDark();
  }
);
const beforeChange = () => {
  return new Promise((resolve) => {
    const isAppearanceTransition =
      document.startViewTransition &&
      !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (!isAppearanceTransition) {
      resolve(true);
      return;
    }

    const switchElement = switchRef.value?.$el;
    const rect = switchElement.getBoundingClientRect();
    const x = rect.left + rect.width / 2;
    const y = rect.top + rect.height / 2;

    const endRadius = Math.hypot(
      Math.max(x, innerWidth - x),
      Math.max(y, innerHeight - y)
    );
    const transition = document.startViewTransition(async () => {
      resolve(true);
      await nextTick();
    });
    transition.ready.then(() => {
      const clipPath = [
        `circle(0px at ${x}px ${y}px)`,
        `circle(${endRadius}px at ${x}px ${y}px)`,
      ];
      document.documentElement.animate(
        {
          clipPath: isDark.value ? clipPath : [...clipPath].reverse(),
        },
        {
          duration: 400,
          easing: "ease-in",
          pseudoElement: isDark.value
            ? "::view-transition-new(root)"
            : "::view-transition-old(root)",
        }
      );
    });
  });
};
</script>

<style lang="scss">
::view-transition-old(root),
::view-transition-new(root) {
  mix-blend-mode: normal;
  animation: none;
}
::view-transition-old(root) {
  z-index: 9999;
}
::view-transition-new(root) {
  z-index: 1;
}
.dark::view-transition-old(root) {
  z-index: 1;
}
.dark::view-transition-new(root) {
  z-index: 9999;
}
</style>
